package com.xebia.pomodoro.action
{
	import com.xebia.pomodoro.event.P2PConnectionEvent;
	import com.xebia.pomodoro.vo.RegisterationInfo;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.NetStatusEvent;
	import flash.net.GroupSpecifier;
	import flash.net.NetConnection;
	import flash.net.NetGroup;


	public class P2PConnection extends EventDispatcher
	{

		private var connection:NetConnection;

		private var group:NetGroup;

		public var groupName:String;


		[Bindable]
		private var _isConnected:Boolean;

		[Bindable(event = "neighborCountUpdate")]
		public function get neighborCount():Number
		{
			return group.neighborCount;
		}

		[Bindable]
		public function get isConnected():Boolean
		{
			return _isConnected;
		}

		private function set isConnected(value:Boolean):void
		{
			_isConnected = value;
		}

		public function P2PConnection()
		{
			connection = new NetConnection();
			connection.maxPeerConnections = 30;
			connection.addEventListener(NetStatusEvent.NET_STATUS, connection_netStatusHandler);
		}

		public function connect(groupname:String):void
		{
			this.groupName = groupname;
			connection.connect("rtmfp:");
		}

		private function connection_netStatusHandler(event:NetStatusEvent):void
		{
			trace("Status: " + event.info.code);

			switch (event.info.level)
			{
				case "status":
				{
					handleConnectionStatusMessages(event.info);
					break;
				}
				case "error":
				{
					handleConnectionErrorEvent(event.info);
					break;
				}
			}
		}

		private function handleConnectionErrorEvent(info:Object):void
		{
			switch (info.code)
			{
				case "NetConnection.Connect.Rejected":
				{
					break;
				}
				case "NetConnection.Connect.Failed":
				{
					break;
				}
				case "NetGroup.Connect.Failed":
				{
					break;
				}
			}
		}

		private function handleConnectionStatusMessages(info:Object):void
		{
			switch (info.code)
			{
				case "NetConnection.Connect.Success":
				{
					setupGroup();
					break;
				}

				case "NetGroup.Connect.Success":
				{
					isConnected = true;
					this.dispatchEvent(new P2PConnectionEvent(P2PConnectionEvent.CONNECTION_SUCCESS));
					break;
				}

				case "NetGroup.Neighbor.Connect":
				{
					var registerationInfo:RegisterationInfo = new RegisterationInfo(connection.nearID, info.neighbor);
					var p2pNeighborConnectEvent:P2PConnectionEvent = new P2PConnectionEvent(P2PConnectionEvent.NEIGHBOR_CONNECT, registerationInfo);
					this.dispatchEvent(p2pNeighborConnectEvent);
					this.dispatchEvent(new Event("neighborCountUpdate"));
					break;
				}

				case "NetGroup.Neighbor.Disconnect":
				{
					var p2pNeighborDisconnectEvent:P2PConnectionEvent = new P2PConnectionEvent(P2PConnectionEvent.NEIGHBOR_DISCONNECT, info.peerID);
					this.dispatchEvent(p2pNeighborDisconnectEvent);
					this.dispatchEvent(new Event("neighborCountUpdate"));
					break;
				}

				case "NetConnection.Connect.Closed":
				{
					isConnected = false;
					break;
				}

				case "NetGroup.Posting.Notify":
				{
					this.dispatchEvent(new P2PConnectionEvent(P2PConnectionEvent.GROUP_POST_RECIEVED, info));
					break;
				}

				case "NetGroup.SendTo.Notify":
				{
					this.dispatchEvent(new P2PConnectionEvent(P2PConnectionEvent.INDIVIDUAL_MESSAGE_RECIEVED, info));
					break;
				}

			}
		}

		private function setupGroup():void
		{
			var groupspec:GroupSpecifier = new GroupSpecifier(groupName);
			groupspec.postingEnabled = true;
			groupspec.ipMulticastMemberUpdatesEnabled = true;
			groupspec.multicastEnabled = true;
			groupspec.routingEnabled = true;
			groupspec.addIPMulticastAddress("225.225.0.1:30303");

			group = new NetGroup(connection, groupspec.groupspecWithAuthorizations());
			group.addEventListener(NetStatusEvent.NET_STATUS, connection_netStatusHandler);
		}

		public function postMessage(message:Object):void
		{
			group.post(message);
		}

		public function sendMessageToAll(message:Object):void
		{
			group.sendToAllNeighbors(message);
		}

		public function sendMessageToNeighbour(message:Object, neighbourAddress:String):void
		{
			group.sendToNearest(message, neighbourAddress);
		}

		public function sendMessageToNeighbourUsingPeerID(message:Object, peerid:String):void
		{
			var groupAddress:String = group.convertPeerIDToGroupAddress(peerid);
			sendMessageToNeighbour(message, groupAddress);
		}

	}
}
